#include "test_timer.h"
#include <sea_statemachine>

using namespace sea;

// -------------------------------------------------------------------------------------------------

class MyTimer : public StateMachine
{
public:
    MyTimer( int param ) : 
      StateMachine( STATEMACHINE_NAME ), 
          m_timer( NULL ),
          m_param( param ) { }
    EVENT_INT( MyTimer, Ev_Int_BeatTimout );
    EVENT_INT( MyTimer, Ev_Int_GameOver );

    ACT( MyTimer, start_my_timer );
    ACT( MyTimer, beat );
    ACT( MyTimer, myexit );
private:
    sea::ref< Timer > m_timer;
    sea::aref m_timerCb;
    int m_param;
};

// -------------------------------------------------------------------------------------------------

SM_DECLARE
(
    timer_test,     // Source code name to be passed to create( )
    MyTimer         // Class name 
    async           // Exec mode

    // States
    {
        Exceptions
        {
            Ev_Sys_Terminate        myexit          nojump
            Ev_Sys_Terminate        exit            nojump
        }
        Sleep 
        {
            Ev_Sys_OnEntry          start_my_timer  Drum
        }
        Drum
        {
            Ev_Int_BeatTimout       beat            nojump
            Ev_Int_GameOver         myexit          nojump
            Ev_Int_GameOver         exit            nojump
        }
    } 
);

// -------------------------------------------------------------------------------------------------

void MyCb( void* ACT_EVENT_PARAM( ) )
{
    SEA_UNUSED_PARAM( );
    aref sm( reinterpret_cast< Object*>( ACT_EVENT_PARAM( ) ) );
    SEA_TRACE( "...cb... " );
}

// -------------------------------------------------------------------------------------------------

ACT_IMPL( MyTimer, start_my_timer ) 
{ 
    SEA_UNUSED_PARAM( );

    Timer* timer = NEW Timer(
        this,
        100,
        10,
        (void*)m_param,
        Ev_Int_BeatTimout( ),
        Ev_Int_GameOver( ) );

    timer->start( );
    m_timer.adopt( timer );

    timer = NEW Timer(
        1000, 1,
        MyCb,
        this );
    timer->start( );
    m_timerCb.adopt( timer );
}

// -------------------------------------------------------------------------------------------------

ACT_IMPL( MyTimer, myexit ) 
{
    SEA_UNUSED_PARAM( );
    m_timer->forget_state_machine( );
}

// -------------------------------------------------------------------------------------------------

ACT_IMPL( MyTimer, beat ) 
{ 
    SEA_UNUSED_PARAM( );
    ASSERT_DEBUG( ( int )ACT_EVENT_PARAM( ) == m_param );

    SEA_TRACE( "...beat... param %d", ACT_EVENT_PARAM( ) );
}

// -------------------------------------------------------------------------------------------------

void test_timer( )
{
    // Launch n async state machines and terminate them
    // in the middle of nowhere
    int n = 20;
    {
        for( int i = 0; i < n; i++ )
        {
            MyTimer* sm = NEW MyTimer( i );
            if( sm->create( 0, timer_test ) != eOk ){ /* Error */}
            if( sm->start( ) != eOk ){ /* Error */ }
            sm->release_ref( );
        }
    }

    Engine::terminate( );

    {
        vector< StateMachine* > all;
        MyTimer* sm = NULL;
        for( int i = 0; i < n; i++ )
        {
            sm = NEW MyTimer( i );
            if( sm->create( 0, timer_test ) != eOk ){ /* Error */}
            all.insert( all.end( ), sm );
        }
        if( sm->start( all ) != eOk ){ /* Error */ }

        for( int i = 0; i < n; i++ )
        {
            all[ i ]->wait_manager_to_finish( );
            all[ i ]->release_ref( );
        }
        all.clear( );

    }
    Engine::terminate( );

    {
        MyTimer* sm = NEW MyTimer( -1 );
        
        if( sm->create( 0, timer_test ) != eOk ){ /* Error */}
        if( sm->start( ) != eOk ){ /* Error */ }

        sm->release_ref( );
    }
    Engine::terminate( );
}

// -------------------------------------------------------------------------------------------------

